package com.csun.cmny.provider.service.impl;

import com.csun.cmny.base.constant.JiGuangConstant;
import com.csun.cmny.base.dto.LoginAuthDto;
import com.csun.cmny.base.enums.ErrorCodeEnum;
import com.csun.cmny.core.support.BaseService;
import com.csun.cmny.provider.constant.Constant;
import com.csun.cmny.provider.dao.*;
import com.csun.cmny.provider.dto.OmcOldLeaveQueryDto;
import com.csun.cmny.provider.exceptions.OmcBizException;
import com.csun.cmny.provider.model.constant.OldOutConstant;
import com.csun.cmny.provider.model.domain.*;
import com.csun.cmny.provider.model.dto.SendMessageRequest;
import com.csun.cmny.provider.model.dto.old_out.*;
import com.csun.cmny.provider.model.dto.revise.GroupPaymentFeeQueryDto;
import com.csun.cmny.provider.model.vo.RpcRoleVo;
import com.csun.cmny.provider.model.vo.old_out.*;
import com.csun.cmny.provider.model.vo.revise.*;
import com.csun.cmny.provider.pojo.NursingGroup;
import com.csun.cmny.provider.pojo.Oldman;
import com.csun.cmny.provider.resolver.CmnyMessageSource;
import com.csun.cmny.provider.service.*;
import com.csun.cmny.provider.vo.MyCommentVo;
import com.csun.cmny.provider.vo.OmcAdjustRefundData;
import com.csun.cmny.util.DateUtil;
import com.csun.cmny.util.PubUtils;
import com.csun.cmny.util.PublicUtil;
import com.github.pagehelper.PageHelper;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import jline.internal.Log;
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.TaskService;
import org.activiti.engine.impl.identity.Authentication;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author chenzheng
 * @description:出院流程服务层
 * @date 2019/9/11 17:52
 */
@Slf4j
@Service
@Transactional
public class OmcOldOutServiceImpl extends BaseService<OmcOldOut> implements OmcOldOutService {

    @Resource
    private OmcOldOutMapper omcOldOutMapper;
    @Resource
    private CmnyMessageSource cmnyMessageSource;
    @Resource
    private UacRpcService uacRpcService;
    @Resource
    private TaskService taskService;
    @Resource
    private OmcActivitiService omcActivitiService;
    @Resource
    private OmcOldOutVarService omcOldOutVarService;
    @Resource
    private OmcCycleExpenseItemMapper omcCycleExpenseItemMapper;
    @Resource
    private OmcReturnFeeConfigService omcReturnFeeConfigService;
    @Resource
    private OmcOldmanPaidExpenseItemService omcOldmanPaidExpenseItemService;
    @Resource
    private OmcExpenseTypeModelCodeService omcExpenseTypeModelCodeService;
    @Resource
    private OmcBillMealService omcBillMealService;
    @Resource
    private OmcOldManBillService omcOldManBillService;
    @Resource
    private OmcGroupService omcGroupService;
    @Resource
    private OmcOldOutSetMealService omcOldOutSetMealService;
    @Resource
    private OmcOldOutSetMealItemService omcOldOutSetMealItemService;
    @Resource
    private OmcOldOutDaysService omcOldOutDaysService;
    @Resource
    private OmcOldManAccountFundsService omcOldManAccountFundsService;
    @Resource
    private OmcNursingRoomBindMapper omcNursingRoomBindMapper;
    @Resource
    private OmcOldOutItemService omcOldOutItemService;
    @Resource
    private OmcOldmanStatusService omcOldmanStatusService;
    @Resource
    private OldmanService oldmanService;
    @Resource
    private BedService bedService;
    @Resource
    private OmcReviseMapper omcReviseMapper;
    @Resource
    private OmcBillBackItemService omcBillBackItemService;
    @Resource
    private OmcBillOutHospitalFeeMapper omcBillOutHospitalFeeMapper;
    @Resource
    private OmcBillSetMealItemService omcBillSetMealItemService;
    @Resource
    private OpcMessageService opcMessageService;
    @Resource
    private OmcOldLeaveService omcOldLeaveService;
    @Resource
    private OmcOldManSupplementMapper omcOldManSupplementMapper;
    @Resource
    private OmcOldmanExpenseItemService omcOldmanExpenseItemService;
    @Resource
    private OmcOldManSupplementService omcOldManSupplementService;

    @Override
    public Integer apply(OldOutDto oldOutDto, LoginAuthDto loginAuthDto) {

        OmcOldOut omcOldOut = new OmcOldOut();

        // 老人Id
        Integer oldmanId = oldOutDto.getOldmanId();
        Long groupId = loginAuthDto.getGroupId();

        log.info("老人出院参数： ===》 老人Id【{}】，出院日期【{}】，类型【{}】，" +
                "死亡描述【{}】，死亡日期【{}】",
                oldmanId, oldOutDto.getLeaveDate(), oldOutDto.getType(),
                oldOutDto.getDeathDesc(), oldOutDto.getDeathDate());

        // 班长才能提交申请
        NursingGroup nursingGroup = new NursingGroup();
        nursingGroup.setUserId(loginAuthDto.getUserId());
        nursingGroup = omcGroupService.selectOne(nursingGroup);
        if (nursingGroup == null) {
            throw new OmcBizException(ErrorCodeEnum.OMC10038001);
        }
        OldOutOldmanQueryDto oldOutOldmanQueryDto = new OldOutOldmanQueryDto();
        oldOutOldmanQueryDto.setNursingGroupId(nursingGroup.getId());
        oldOutOldmanQueryDto.setGroupId(loginAuthDto.getGroupId());

        // 根据班组查询看护的房间
        List<Integer> roomIdList = omcNursingRoomBindMapper
                .queryRoomIdListByNursingGroupId(oldOutOldmanQueryDto.getNursingGroupId());
        if (PublicUtil.isEmpty(roomIdList)) {
            throw new OmcBizException(ErrorCodeEnum.OMC10038011);
        }
        oldOutOldmanQueryDto.setRoomIdList(roomIdList);
        oldOutOldmanQueryDto.setGroupId(loginAuthDto.getGroupId());
        oldOutOldmanQueryDto.setOldmanId(oldmanId);
        List<OldOutOldmanVo> oldOutOldmanVoList = omcOldOutMapper.queryOldmanList(oldOutOldmanQueryDto);
        if (PublicUtil.isEmpty(oldOutOldmanVoList)) {
            throw new OmcBizException(ErrorCodeEnum.OMC10038043);
        }
        BeanUtils.copyProperties(oldOutOldmanVoList.get(0), omcOldOut);

        // 老人是否可以出院
       // omcOldmanStatusService.oldmanOutIng(oldmanId);
        Oldman oldman = new Oldman();
        oldman.setOldmanId(oldOutDto.getOldmanId());
        Oldman old = oldmanService.selectByOld(oldman);

        //校验老人是否在可出院状态
        switch (old.getStatus()) {
            case Constant.LEAVE_ING :
                throw new OmcBizException(ErrorCodeEnum.OMC10031202);
            case Constant.REVISE_ING :
                throw new OmcBizException(ErrorCodeEnum.OMC10031203);
            case Constant.OLD_OUT_ING :
                throw new OmcBizException(ErrorCodeEnum.OMC10031204);
        }

        //校验是否有未缴费的账单
        OmcOldManBill omcOldManBill = new OmcOldManBill();
        omcOldManBill.setOldManId(oldOutDto.getOldmanId().longValue());
        List<OmcOldManBill> select = omcOldManBillService.select(omcOldManBill);
        for (OmcOldManBill oldManBill : select) {
            if (oldManBill.getIsPay()!=1){
                throw new OmcBizException(ErrorCodeEnum.OMC10031212);
            }
        }

        // ************** 参数校验 ************** //
        // 老人死亡参数校验
        if (oldOutDto.getType().equals(OldOutConstant.OLD_OUT_TYPE_DEATH_IN)
                || oldOutDto.getType().equals(OldOutConstant.OLD_OUT_TYPE_DEATH_OUT)) {
            // 死亡日期 && 死亡描述不能为空
            Preconditions.checkArgument(PublicUtil.isNotEmpty(oldOutDto.getDeathDesc()),
                    cmnyMessageSource.getMessage("out.death.desc.null", null));

            Preconditions.checkArgument(PublicUtil.isNotEmpty(oldOutDto.getDeathDate()),
                    cmnyMessageSource.getMessage("out.death.date.null", null));

            Preconditions.checkArgument(PubUtils.is_YYY_MM_DD(oldOutDto.getDeathDate()),
                    cmnyMessageSource.getMessage("out.death.date.error", null));

            omcOldOut.setDeathDate(oldOutDto.getDeathDesc());
            omcOldOut.setDeathDesc(oldOutDto.getDeathDesc());
        }

        /**
         * 校验 -- 不能早于最后一条调整的日期
         */
        String reviseDate = omcReviseMapper.queryLastReviseDateByOldmanId(oldmanId);
        if (PublicUtil.isNotEmpty(reviseDate) && oldOutDto.getLeaveDate().compareTo(reviseDate) <= 0) {
            log.warn("reviseDate ==> {}, date ==> {}", reviseDate, oldOutDto.getLeaveDate());
            throw new OmcBizException(ErrorCodeEnum.OMC10031108);
        }

        /**
         * 不能早于入院日期
         */
        if (oldOutDto.getLeaveDate().compareTo(omcOldOut.getInDate()) <= 0) {
            throw new OmcBizException(ErrorCodeEnum.OMC10031109);
        }

        omcOldOut.setLeaveDate(oldOutDto.getLeaveDate());
        omcOldOut.setType(oldOutDto.getType());
        omcOldOut.setOldmanId(oldmanId);
        omcOldOut.setGroupId(groupId);
        omcOldOut.setNursingGroupId(nursingGroup.getId());
        omcOldOut.setUpdateInfo(loginAuthDto);
        Integer result = omcOldOutMapper.insertSelective(omcOldOut);
        if (result < 1) {
            throw new OmcBizException(ErrorCodeEnum.OMC10031101);
        }
        Long oldOutId = omcOldOut.getId();

        // 计算出院退费周期数
        OldOutDaysDto oldOutDaysDto = new OldOutDaysDto();
        oldOutDaysDto.setGroupId(groupId);
        oldOutDaysDto.setInDate(DateUtil.stringToDate(omcOldOut.getInDate()));
        oldOutDaysDto.setOutDate(DateUtil.stringToDate(oldOutDto.getLeaveDate()));
        OldOutDaysVo oldOutDaysVo = omcReturnFeeConfigService.queryOldOutDaysVo(oldOutDaysDto);
        log.info("出院退费周期数 oldOutDaysVo = {}", oldOutDaysVo.toString());

        int returnDays = oldOutDaysVo.getReturnDays();
        BigDecimal returnPercent = oldOutDaysVo.getReturnPercent();
        BigDecimal usedPercent = oldOutDaysVo.getUsedPercent();

        // 查询该老人的缴费信息
        Map<Long, OldmanPaymentFeeVo> oldmanPaymentFeeVoMap = Maps.newHashMap();
        GroupPaymentFeeQueryDto groupPaymentFeeQueryDto = new GroupPaymentFeeQueryDto();
        groupPaymentFeeQueryDto.setOldmanId(oldmanId);
        groupPaymentFeeQueryDto.setIsOutReturn(1);
        List<OldmanPaymentFeeVo> oldmanPaymentFeeVoList = omcCycleExpenseItemMapper
                .queryOldmanPaymentFeeByOldmanId(groupPaymentFeeQueryDto);
        Map<Long, OmcOldOutItem> omcOldOutItemOutReturnMap = Maps.newHashMap();
        if (PublicUtil.isEmpty(oldmanPaymentFeeVoList)) {
            log.warn("老人无缴费信息");
        } else {
//            oldmanPaymentFeeVoMap = oldmanPaymentFeeVoList.stream()
//                    .collect(Collectors.toMap(OldmanPaymentFeeVo::getExpenseItemId, item -> item));
            for (OldmanPaymentFeeVo opfv : oldmanPaymentFeeVoList) {
                OmcOldOutItem omcOldOutItemOut = getOmcOldOutItemOut(opfv, loginAuthDto, returnPercent);    // 出院退费
                omcOldOutItemOut.setAdjustOrder(Constant.OLD_OUT_ADJUST_OUT_RETURN);
                omcOldOutItemOut.setOldOutId(oldOutId);

                omcOldOutItemOutReturnMap.put(opfv.getExpenseItemId(), omcOldOutItemOut);
            }
        }

        // 老人出院 - 出院退费项 & 入院退费项 & 出院收费项
        List<OmcOldOutItem> omcOldOutItemList = Lists.newArrayList();

        // --- 入院退费 --- //   // 查询退费项目 （一次性 & 周期 & 次数）
        // 查询入院的时候收取的费用，并且"是否退费"(is_out_return)为"是"(1)
        OldmanPaidQueryDto oldmanPaidQueryDto = new OldmanPaidQueryDto();
        oldmanPaidQueryDto.setOldmanId(oldmanId);
        oldmanPaidQueryDto.setIsOutReturn(Constant.EXPENSE_TYPE_OUT_RETURN_YES);
        oldmanPaidQueryDto.setModelCode(Constant.EXPENSE_TYPE_MODEL_CODE_IN);
        List<OldmanPaymentFeeVo> oldmanCheckInReturnFeeVoList = omcOldmanPaidExpenseItemService.queryPaidItemList(oldmanPaidQueryDto);
        if (PublicUtil.isEmpty(oldmanCheckInReturnFeeVoList)) {
            log.warn("入院退费 ===》 无入院退费项");
        }

        // TODO 需要区分在套餐还是不在套餐中
        /**
         * 入院项目出院退费
         *     若在套餐中，则按照套餐计算
         *     若不在套餐中，则按照原价计算
         */
        Map<Long, OmcOldOutItem> omcOldOutItemInReturnMap = Maps.newHashMap();
        for (OldmanPaymentFeeVo opfv : oldmanCheckInReturnFeeVoList) {
            OmcOldOutItem omcOldOutItemInReturn = getOmcOldOutItemInReturn(opfv, loginAuthDto);    // 入院退费
            omcOldOutItemInReturn.setOldOutId(oldOutId);

            omcOldOutItemInReturnMap.put(omcOldOutItemInReturn.getExpenseItemId(), omcOldOutItemInReturn);
        }

        // --- 出院收费 --- //
        // 查询该机构的收费信息
        boolean isOutCharge = true;
        groupPaymentFeeQueryDto = new GroupPaymentFeeQueryDto();
        groupPaymentFeeQueryDto.setGroupId(loginAuthDto.getGroupId());
        groupPaymentFeeQueryDto.setModelCode(Constant.EXPENSE_TYPE_MODEL_CODE_OUT);
        List<GroupPaymentFeeVo> groupPaymentFeeVoList = omcExpenseTypeModelCodeService
                .queryGroupPaymentFeeByGroupId(groupPaymentFeeQueryDto);
        if (PublicUtil.isEmpty(groupPaymentFeeVoList)) {
            log.warn("出院收费 ===》 无出院收费项");
            isOutCharge = false;
        }


        BigDecimal oldmanCheckOutChargeFee = BigDecimal.ZERO;   // 出院收取的费用
        if (isOutCharge) {  // 校验出院收费列表
            if (PublicUtil.isEmpty(oldOutDto.getOutFeeItemDtoList())) {
                throw new OmcBizException(ErrorCodeEnum.OMC10031105);
            }
            // 将出院收费项转map
            Map<Long, OutFeeItemDto> outFeeItemDtoMap = oldOutDto.getOutFeeItemDtoList().stream()
                    .collect(Collectors.toMap(OutFeeItemDto::getExpenseItemId, item -> item));

            Map<Long, GroupPaymentFeeItemVo> groupPaymentFeeItemVoMap = Maps.newHashMap();
            for (GroupPaymentFeeVo gpfv : groupPaymentFeeVoList) {
                for (ExpenseItem item : gpfv.getExpenseItemList()) {
                    GroupPaymentFeeItemVo gpfiv = new GroupPaymentFeeItemVo();
                    BeanUtils.copyProperties(item, gpfiv);
                    BeanUtils.copyProperties(gpfv, gpfiv);
                    groupPaymentFeeItemVoMap.put(item.getExpenseItemId(), gpfiv);

                    OutFeeItemDto ofid = outFeeItemDtoMap.get(item.getExpenseItemId());
                    if (PublicUtil.isEmpty(ofid)) {
                        throw new OmcBizException(ErrorCodeEnum.OMC10031106);
                    }
                    OmcOldOutItem omcOldOutItemCharge = getOmcOldOutItemCharge(gpfv, item, ofid, loginAuthDto);    // 出院收费
                    omcOldOutItemCharge.setOldOutId(oldOutId);
                    omcOldOutItemList.add(omcOldOutItemCharge);
                    oldmanCheckOutChargeFee = oldmanCheckOutChargeFee.add(omcOldOutItemCharge.getTotalFee());
                }
            }
        }
        omcOldOut.setChargeTotal(oldmanCheckOutChargeFee);

        // --- 套餐退费 --- //
        // 套餐退费金额计算
        BigDecimal packFee = BigDecimal.ZERO;
        // 判断调整后是否选中调整前的套餐服务项

        // 查询老人最近一次的入院账单Id
        Long billId = omcOldManBillService.queryOldmanCheckInBillId(oldmanId);
        if (billId == null) {
            throw new OmcBizException(ErrorCodeEnum.OMC10038043);
        }

        // 查询老人入院选择的套餐
        Map<Long, OldmanSetMealItemVo> oldmanSetMealItemVoMap = Maps.newHashMap();
        List<OldmanSetMealVo> oldmanSetMealVoList = omcBillMealService.queryOldmanSetMealByBillId(billId);
        if (PublicUtil.isNotEmpty(oldmanSetMealVoList)) {
            // 老人选中套餐
            for (OldmanSetMealVo osmv : oldmanSetMealVoList) {
                OmcOldOutSetMeal omcOldOutSetMeal = getOmcOldOutSetMeal(osmv, loginAuthDto);
                omcOldOutSetMeal.setOldOutId(oldOutId);
                BigDecimal totalFee = BigDecimal.ZERO;
                List<OmcOldOutSetMealItem> omcOldOutSetMealItemList = Lists.newArrayList();
                for (OldmanSetMealItemVo osmiv : osmv.getOldmanSetMealItemVoList()) {
                    OmcOldOutSetMealItem omcOldOutSetMealItem = getOmcOldOutSetMealItem(osmiv, loginAuthDto);
                    BigDecimal item_total_fee = BigDecimal.ZERO;
                    // OldmanPaymentFeeVo opfv = oldmanPaymentFeeVoMap.get(osmiv.getExpenseItemId());
                    OmcOldOutItem omcOldOutItemOut = omcOldOutItemOutReturnMap.get(osmiv.getExpenseItemId());
                    // 套餐剩余次数
                    BigDecimal setMealReturnPercent = osmiv.getUsedDegree().add(osmiv.getResidueDegree());
                    if (setMealReturnPercent.compareTo(BigDecimal.ZERO) <= 0) {
                        continue;
                    }
                    OmcOldOutItem omcOldOutItemIn = omcOldOutItemInReturnMap.get(osmiv.getExpenseItemId());
                    if (PublicUtil.isNotEmpty(omcOldOutItemIn)) {
                        // 入院套餐退费
                        item_total_fee = setMealReturnPercent.multiply(osmiv.getReturnStandard()).setScale(2, BigDecimal.ROUND_HALF_UP);
                        omcOldOutItemIn.setInReturn(false);

                        omcOldOutSetMealItem.setResidueDegree(setMealReturnPercent);
                        omcOldOutSetMealItem.setTotalFee(item_total_fee);   // 单项退款合计
                        totalFee = totalFee.add(item_total_fee);            // 单个套餐退款合计
                        oldmanSetMealItemVoMap.put(osmiv.getExpenseItemId(), osmiv);
                        omcOldOutSetMealItemList.add(omcOldOutSetMealItem);
                    } else {
                        if (PublicUtil.isEmpty(omcOldOutItemOut)) {
                            // 套餐项目不在周期收费中，不进行退费
                            // 如果使用次数是0，剩余次数是1，说明是入院退费
                            log.warn("套餐项目不在周期收费中 ====》 ExpenseItemId =【{}】", osmiv.getExpenseItemId());
                        } else {
                            // 出院不参与退费
                            omcOldOutItemOut.setOutReturn(false);
                            // 该项需要进行退费
                            if (setMealReturnPercent.compareTo(usedPercent) <= 0) { // 套餐已经使用完了
                                // 按原价退
                                omcOldOutItemOut.setOutReturn(true);
                            } else {
                                setMealReturnPercent = setMealReturnPercent.subtract(usedPercent); // 大于0
                                omcOldOutSetMealItem.setResidueDegree(setMealReturnPercent);
                                // 项目一剩余次数 * 项目一退费标准
                                item_total_fee = setMealReturnPercent.multiply(osmiv.getReturnStandard()).setScale(2, BigDecimal.ROUND_HALF_UP);
                                if (setMealReturnPercent.compareTo(returnPercent) >= 0) {
                                    // 套餐全部退
                                } else {
                                    // 套餐不够退

                                    // 项目原价退
                                    setMealReturnPercent = returnPercent.subtract(setMealReturnPercent);
                                    omcOldOutItemOut.setResidueDegree(setMealReturnPercent);
                                    omcOldOutItemOut.setTotalFee(setMealReturnPercent.multiply(omcOldOutItemOut.getActualFee()).setScale(2, BigDecimal.ROUND_HALF_UP));
                                    omcOldOutItemOut.setOutReturn(true);
                                }
                                //
                                omcOldOutSetMealItem.setTotalFee(item_total_fee);   // 单项退款合计
                                totalFee = totalFee.add(item_total_fee);            // 单个套餐退款合计
                                oldmanSetMealItemVoMap.put(osmiv.getExpenseItemId(), osmiv);
                                omcOldOutSetMealItemList.add(omcOldOutSetMealItem);
                            }
                            // 项目一剩余次数 * 项目一退费标准
                            // item_total_fee = item_total_fee.add(osmiv.getResidueDegree().multiply(osmiv.getReturnStandard()));
                        }
                    }
                    // copyOldmanSetMealItemVoMap.put(osmiv.getExpenseItemId(), osmiv);
                }
                packFee = packFee.add(totalFee);    // 套餐退费合计
                omcOldOutSetMeal.setOldOutId(oldOutId);
                omcOldOutSetMeal.setTotalFee(totalFee);
                if (totalFee.compareTo(BigDecimal.ZERO) > 0) {
                    // 老人出院套餐入库
                    omcOldOutSetMealService.save(omcOldOutSetMeal);
                    // 老人出院套餐项入库
                    omcOldOutSetMealItemService.batchSaveWithSetMealId(omcOldOutSetMealItemList, omcOldOutSetMeal.getId());
                }
            }
        }

        // 套餐退款合计
        omcOldOut.setSetMealTotal(packFee);

        // 遍历筛选后套餐项 -- 套餐退费
//        for (OldmanSetMealItemVo osmiv : oldmanSetMealItemVoMap.values()) {
//            // 项目一剩余次数 * 项目一退费标准
//            packFee = packFee.add(osmiv.getResidueDegree().multiply(osmiv.getReturnStandard()));
//            log.info("套餐退费 ===》收费项目Id【{}】，名称【{}】剩余次数【{}】的退费标准【{}】，退费金额【{}】",
//                    osmiv.getExpenseItemId(), osmiv.getExpenseItemName(), osmiv.getResidueDegree(),
//                    osmiv.getReturnStandard(), packFee);
//        }
        // 判断退费金额是否正确
//        packFee = packFee.setScale(2, BigDecimal.ROUND_HALF_UP);
//        log.info("套餐退费金额 ==》【{}】", packFee);

        // 周期退费项目
        BigDecimal oldmanCheckOutReturnFee = BigDecimal.ZERO;
        BigDecimal oldmanCheckInReturnFee = BigDecimal.ZERO;
//        for (OldmanPaymentFeeVo opfv : oldmanPaymentFeeVoList) {
//            if (opfv.getIsOutReturn().equals(Constant.EXPENSE_TYPE_OUT_RETURN_YES)
//                    && opfv.isOutReturn()) {
//                oldmanCheckOutReturnFee = oldmanCheckOutReturnFee.add(opfv.getActualFee());
//                log.info("老人出院计算 ===》 收费项目Id【{}】,名称【{}】，收费标准【{}】，类别减免【{}】，人工减免【{}】，实际收费【{}】",
//                        opfv.getExpenseItemId(), opfv.getItemName(), opfv.getItemFee(),
//                        opfv.getUserRateRefief(), opfv.getUserRateRefief(), opfv.getActualFee());
//
//                OmcOldOutItem omcOldOutItemInOut = getOmcOldOutItemInOut(opfv, loginAuthDto);    // 入院退费
//                omcOldOutItemInOut.setAdjustOrder(Constant.OLD_OUT_ADJUST_OUT_RETURN);
//                omcOldOutItemInOut.setOldOutId(oldOutId);
//                omcOldOutItemList.add(omcOldOutItemInOut);
//            }
//        }
        // 入院项目退费合计
        for (OmcOldOutItem in : omcOldOutItemInReturnMap.values()) {
            if (in.isInReturn()) {
                omcOldOutItemList.add(in);
                oldmanCheckInReturnFee = oldmanCheckInReturnFee.add(in.getTotalFee());
            }
            System.out.println("入院项目退费 ==> " + in);
        }

        // 出院项目退费合计
        for (OmcOldOutItem out : omcOldOutItemOutReturnMap.values()) {
            if (out.isOutReturn()) {
                omcOldOutItemList.add(out);
                oldmanCheckOutReturnFee = oldmanCheckOutReturnFee.add(out.getTotalFee());
            }
            System.out.println("出院项目退费 ==> " + out);
        }
        log.info("老人入院收费合计 ===》【{}】", oldmanCheckOutChargeFee);
        log.info("老人入院退费合计 ===》【{}】", oldmanCheckInReturnFee);
        log.info("老人出院退费合计 ===》【{}】", oldmanCheckOutReturnFee);
        log.info("老人套餐退费合计 ===》【{}】", packFee);

        omcOldOutItemService.batchSave(omcOldOutItemList);

        // 是否已经有周期缴费

        // 天数退款
        List<OmcOldOutDays> omcOldOutDaysList = Lists.newArrayList();

        // 请假退费
        // TODO 从请假中查询
        OmcOldLeaveQueryDto omcOldLeaveQueryDto = new OmcOldLeaveQueryDto();
        omcOldLeaveQueryDto.setOldManId(oldmanId.longValue());
        omcOldLeaveQueryDto.setAdjustDate(oldOutDto.getLeaveDate());
        omcOldLeaveQueryDto.setGroupId(groupId);
        OmcAdjustRefundData omcAdjustRefundData = omcOldLeaveService.showLeaveRefundFee(omcOldLeaveQueryDto);
        if (omcAdjustRefundData == null) {
            omcAdjustRefundData = new OmcAdjustRefundData();
        }

        OmcOldOutDays omcOldOutDaysLeave = new OmcOldOutDays();
        omcOldOutDaysLeave.setUpdateInfo(loginAuthDto);
        omcOldOutDaysLeave.setType(Constant.OLD_OUT_DAYS_TYPE_LEAVE);
        omcOldOutDaysLeave.setDays(omcAdjustRefundData.getRefundDays());
        omcOldOutDaysLeave.setTotalFee(omcAdjustRefundData.getRefundFee());
        omcOldOutDaysLeave.setOldOutId(oldOutId);

        omcOldOutDaysList.add(omcOldOutDaysLeave);

        /**
         * 出院退费周期数 = （周期最大天数 - 实际出院天数） / 周期总天数
         * ** TIPS **
         * 1、周期最大天数 - 实际出院天数 < 0，出院退费周期数为0
         * 2、若出院退费周期数 > 1，出院退费周期数据为1
         */
        // 查询最大周期数，周期总条数，请假退费天数，扣除请假天数

        OmcOldOutDays omcOldOutDaysCurrent = new OmcOldOutDays();
        omcOldOutDaysCurrent.setUpdateInfo(loginAuthDto);
        omcOldOutDaysCurrent.setType(Constant.OLD_OUT_DAYS_TYPE_CURRENT);
        omcOldOutDaysCurrent.setDays(returnDays);
        // 本月剩余天数退款合计 = 出院退款合计 + 入院退款合计
        BigDecimal itemDaysTotal = oldmanCheckOutReturnFee.add(oldmanCheckInReturnFee);
        omcOldOutDaysCurrent.setTotalFee(itemDaysTotal);
        omcOldOutDaysCurrent.setOldOutId(oldOutId);
        omcOldOutDaysList.add(omcOldOutDaysCurrent);

        omcOldOutDaysService.batchSave(omcOldOutDaysList);

        omcOldOut.setDaysTotal(omcOldOutDaysCurrent.getTotalFee().add(omcOldOutDaysLeave.getTotalFee()));

        // 退款合计 =  天数退款合计（本月剩余天数退款合计 + 请假天数退款合计） + 套餐退款合计
        BigDecimal itemsTotal = omcOldOut.getDaysTotal().add(packFee);
        omcOldOut.setItemsTotal(itemsTotal);

        // 老人资金账户
        OmcOldManAccountFunds omcOldManAccountFunds = omcOldManAccountFundsService
                .queryByOldmanId(oldmanId);
        if (PublicUtil.isEmpty(omcOldManAccountFunds)) {
            throw new OmcBizException(ErrorCodeEnum.OMC10038030);
        }

        // 出院前余额
        omcOldOut.setRemainder(omcOldManAccountFunds.getRemainder());
        // 出院后余额 = 余额 - 出院收费 - 出院退费
        BigDecimal totalPay = omcOldManAccountFunds.getRemainder().subtract(oldmanCheckOutChargeFee).add(itemsTotal);
        // 应缴合计 = 0 - 出院后余额
        omcOldOut.setTotalPay(BigDecimal.ZERO.subtract(totalPay));
        // 消费总额 = 出院应缴项缴费合计
        omcOldOut.setMonetary(oldmanCheckOutChargeFee);
        // TODO 资金账户销户

        /**
         * 出院剩余周期数退费
         *
         * 退费类别：被设置为退费的类别，才能进行退费处理
         * 出院剩余周期数退费公式：
         *     匹配到周期缴费项目，和出院退费类别匹配，匹配到哪些项目可以退款
         *     出院退费金额 = 退款项目金额之和（不包含套餐）* 出院退费周期数 +
         *                  （套餐退费公式 * 出院退费周期数）
         *
         * 出院退费公式：
         *     出院退费金额 = 余额 + 入院缴费项（设置为可以退款的项）之和 -
         *                   出院缴纳费用之和 + 请假退费金额 + 出院周期退费金额
         */

        // 启动流程
        Map<String, Object> variables = new HashMap<String, Object>();
        variables.put(OldOutConstant.OLD_OUT_VAR_SERVICE, omcOldOutVarService
                .queryVarByGroupIdAndKey(loginAuthDto.getGroupId(), OldOutConstant.OLD_OUT_VAR_SERVICE));
        variables.put(OldOutConstant.OLD_OUT_VAR_ADMIT, omcOldOutVarService
                .queryVarByGroupIdAndKey(loginAuthDto.getGroupId(), OldOutConstant.OLD_OUT_VAR_ADMIT));
        variables.put(OldOutConstant.OLD_OUT_VAR_MEDICAL, omcOldOutVarService
                .queryVarByGroupIdAndKey(loginAuthDto.getGroupId(), OldOutConstant.OLD_OUT_VAR_MEDICAL));
        variables.put(OldOutConstant.OLD_OUT_VAR_CHARGE, omcOldOutVarService
                .queryVarByGroupIdAndKey(loginAuthDto.getGroupId(), OldOutConstant.OLD_OUT_VAR_CHARGE));

        ProcessInstance processInstance = omcActivitiService
                .startProcessInstanceByKeyAndTenantId(OldOutConstant.PROCESS_KEY_OLD_OUT,
                        variables, loginAuthDto.getGroupId());

        // 查询当前任务
        Task task = omcActivitiService.getTaskByProcessInstanceId(processInstance.getProcessInstanceId());

        // 添加批注
        omcActivitiService.addTaskComment(task, loginAuthDto.getUserName() + "[班长]", "提交申请");

        // 完成老人出院申请
        taskService.complete(task.getId());

        omcOldOut.setState(OldOutConstant.OLD_OUT_STATE_APPLY);
        omcOldOut.setProcessInstanceId(processInstance.getProcessInstanceId());
        result = omcOldOutMapper.updateByPrimaryKeySelective(omcOldOut);
        if (result < 1) {
            throw new OmcBizException(ErrorCodeEnum.OMC10031101);
        }

        //创建推送请求对象 班长申请-》服务部长确认
        SendMessageRequest sendMessageRequest = new SendMessageRequest();
        sendMessageRequest.setMsgCode(OldOutConstant.OUT_FLOW_NURSING_APPLY);
        sendMessageRequest.setGroupId(groupId);
        opcMessageService.pushWithMsgCode(sendMessageRequest);

        return result;
    }

    private OmcOldOutItem getOmcOldOutItemOut(OldmanPaymentFeeVo opfv, LoginAuthDto loginAuthDto, BigDecimal returnPercent) {

        OmcOldOutItem omcOldOutItem = new OmcOldOutItem();
        omcOldOutItem.setUpdateInfo(loginAuthDto);
        BeanUtils.copyProperties(opfv, omcOldOutItem);
        omcOldOutItem.setAdjustOrder(Constant.OLD_OUT_ADJUST_OUT_RETURN);
        omcOldOutItem.setTotalFee(returnPercent.multiply(omcOldOutItem.getActualFee()).setScale(2, BigDecimal.ROUND_HALF_UP));
        omcOldOutItem.setResidueDegree(returnPercent);

        return omcOldOutItem;
    }

    private OmcOldOutSetMealItem getOmcOldOutSetMealItem(OldmanSetMealItemVo osmiv, LoginAuthDto loginAuthDto) {

        OmcOldOutSetMealItem omcOldOutSetMealItem = new OmcOldOutSetMealItem();
        omcOldOutSetMealItem.setUpdateInfo(loginAuthDto);
        BeanUtils.copyProperties(osmiv, omcOldOutSetMealItem);
        omcOldOutSetMealItem.setItemFee(osmiv.getChargeStandard());
        omcOldOutSetMealItem.setItemName(osmiv.getExpenseItemName());
        omcOldOutSetMealItem.setItemType(osmiv.getExpenseTypeName());


        return omcOldOutSetMealItem;
    }

    private OmcOldOutSetMeal getOmcOldOutSetMeal(OldmanSetMealVo osmv, LoginAuthDto loginAuthDto) {

        OmcOldOutSetMeal omcOldOutSetMeal = new OmcOldOutSetMeal();
        omcOldOutSetMeal.setUpdateInfo(loginAuthDto);
        BeanUtils.copyProperties(osmv, omcOldOutSetMeal);

        return omcOldOutSetMeal;
    }

    private OmcOldOutItem getOmcOldOutItemCharge(GroupPaymentFeeVo gpfv,
                                                 ExpenseItem item, OutFeeItemDto ofid, LoginAuthDto loginAuthDto) {

        OmcOldOutItem omcOldOutItem = new OmcOldOutItem();

        omcOldOutItem.setUpdateInfo(loginAuthDto);
        BeanUtils.copyProperties(gpfv, omcOldOutItem);
        BeanUtils.copyProperties(item, omcOldOutItem);
        omcOldOutItem.setItemType(gpfv.getExpenseTypeName());
        omcOldOutItem.setRemark(ofid.getExpenseItemRemark());
        omcOldOutItem.setTotalFee(ofid.getExpenseItemFee());
        omcOldOutItem.setAdjustOrder(Constant.OLD_OUT_ADJUST_OUT_CHARGE);

        return omcOldOutItem;

    }

    private OmcOldOutItem getOmcOldOutItemInReturn(OldmanPaymentFeeVo opfv, LoginAuthDto loginAuthDto) {

        OmcOldOutItem omcOldOutItem = new OmcOldOutItem();

        omcOldOutItem.setUpdateInfo(loginAuthDto);
        BeanUtils.copyProperties(opfv, omcOldOutItem);
        omcOldOutItem.setTotalFee(opfv.getActualFee());
        omcOldOutItem.setAdjustOrder(Constant.OLD_OUT_ADJUST_IN_RETURN);

        return omcOldOutItem;
    }

    @Override
    public Integer serviceConfirm(OldOutConfirmDto oldOutConfirmDto, LoginAuthDto loginAuthDto) {
        String processInstanceId;

        // 查询订单是否存在
        OmcOldOut omcOldOutQuery = omcOldOutMapper.selectByPrimaryKey(oldOutConfirmDto.getId());
        if (PublicUtil.isEmpty(omcOldOutQuery)) {
            throw new OmcBizException(ErrorCodeEnum.OMC10032005);
        }

        // 获取当前用户角色
        List<RpcRoleVo> roleVoList = uacRpcService.queryRoleListByUserId(loginAuthDto.getUserId());
        List<String> roleCodeList = roleVoList.stream().map(r -> r.getRoleCode()).collect(Collectors.toList());

        processInstanceId = omcOldOutQuery.getProcessInstanceId();
        Task task = taskService.createTaskQuery()
                .taskTenantId(loginAuthDto.getGroupId().toString())
                .processDefinitionKey(OldOutConstant.PROCESS_KEY_OLD_OUT)
                .taskCandidateGroupIn(roleCodeList)
                .processInstanceId(processInstanceId)
                .taskDefinitionKey(OldOutConstant.OLD_OUT_TASK_SERVICE_CONFIRM)
                .singleResult();

        if (PublicUtil.isEmpty(task)) {
            // TODO 老人出院任务不存在
            Log.error("老人出院任务不存在");
             throw new OmcBizException(ErrorCodeEnum.OMC10032008);
        }

        String comment = OldOutConstant.OLD_OUT_COMMENT_SERVICE_CONFIRM;
        Integer state = OldOutConstant.OLD_OUT_STATE_SERVICE_AGREE;

        // 设置用户id
        Authentication.setAuthenticatedUserId(loginAuthDto.getUserName() + "[服务部]");
        // 添加批注信息
        taskService.addComment(task.getId(), processInstanceId, comment);

        // 完成任务
        taskService.complete(task.getId());

        OmcOldOut omcOldOut = new OmcOldOut();
        omcOldOut.setId(oldOutConfirmDto.getId());
        omcOldOut.setUpdateInfo(loginAuthDto);
        omcOldOut.setState(state);

        //创建推送请求 服务部长确认-》
        /**
         * @date    2019-12-25
         * @author  chisj
         * @desc    服务部长审批 --> 接待确认
         */
//        SendMessageRequest sendMessageRequest = new SendMessageRequest();
//        sendMessageRequest.setMsgCode(OldOutConstant.OUT_FLOW_SERVICE_CONFIRM);
//        sendMessageRequest.setGroupId(loginAuthDto.getGroupId());
//        opcMessageService.pushWithMsgCode(sendMessageRequest);

        /**************** 医疗部长审批 ****************/
        task = taskService.createTaskQuery()
                .taskTenantId(loginAuthDto.getGroupId().toString())
                .processDefinitionKey(OldOutConstant.PROCESS_KEY_OLD_OUT)
                .processInstanceId(processInstanceId)
                .singleResult();
        String msg = OldOutConstant.OLD_OUT_VAR_MSG_CONFIRM;
        state = OldOutConstant.OLD_OUT_STATE_MEDICAL_AGREE;
        comment = OldOutConstant.OLD_OUT_COMMENT_MEDICAL_AGREE;

        // 设置用户id
        // Authentication.setAuthenticatedUserId("[医疗部]");
        // 添加批注信息
        // taskService.addComment(task.getId(), processInstanceId, comment);

        taskService.setVariable(task.getId(), OldOutConstant.OLD_OUT_VAR_MSG, msg);

        SendMessageRequest sendMessageRequest = new SendMessageRequest();
        sendMessageRequest.setGroupId(loginAuthDto.getGroupId());
        sendMessageRequest.setMsgCode(OldOutConstant.OUT_FLOW_MEDICAL_AGREE);
        opcMessageService.pushWithMsgCode(sendMessageRequest);

        // 完成任务
        taskService.complete(task.getId());

        omcOldOut.setState(state);
        /**************** 医疗部长审批 ****************/

        return omcOldOutMapper.updateByPrimaryKeySelective(omcOldOut);
    }

    @Override
    public Integer medicalApproval(OldOutApprovalDto oldOutApprovalDto, LoginAuthDto loginAuthDto) {

        String processInstanceId;

        // 查询订单是否存在
        OmcOldOut omcOldOutQuery = omcOldOutMapper.selectByPrimaryKey(oldOutApprovalDto.getId());
        if (PublicUtil.isEmpty(omcOldOutQuery)) {
            throw new OmcBizException(ErrorCodeEnum.OMC10032005);
        }

        // 获取当前用户角色
        List<RpcRoleVo> roleVoList = uacRpcService.queryRoleListByUserId(loginAuthDto.getUserId());
        List<String> roleCodeList = roleVoList.stream().map(r -> r.getRoleCode()).collect(Collectors.toList());

        processInstanceId = omcOldOutQuery.getProcessInstanceId();
        Task task = taskService.createTaskQuery()
                .taskTenantId(loginAuthDto.getGroupId().toString())
                .processDefinitionKey(OldOutConstant.PROCESS_KEY_OLD_OUT)
                .taskCandidateGroupIn(roleCodeList)
                .processInstanceId(processInstanceId)
                .taskDefinitionKey(OldOutConstant.OLD_OUT_TASK_MEDICAL_CONFIRM)
                .singleResult();

        if (PublicUtil.isEmpty(task)) {
            Log.error("老人出院任务不存在");
            throw new OmcBizException(ErrorCodeEnum.OMC10032008);
        }

        //String comment = OldOutConstant.OLD_OUT_COMMENT_MEDICAL_REFUSE;
        String comment = oldOutApprovalDto.getComment();
        Integer state = OldOutConstant.OLD_OUT_STATE_SERVICE_REFUSE;
        String msg = OldOutConstant.OLD_OUT_VAR_MSG_REFUSE;

        if (oldOutApprovalDto.getState().equals(OldOutConstant.OLD_OUT_APRV_STATE_YES)) {
            msg = OldOutConstant.OLD_OUT_VAR_MSG_CONFIRM;
            state = OldOutConstant.OLD_OUT_STATE_MEDICAL_AGREE;
            comment = OldOutConstant.OLD_OUT_COMMENT_MEDICAL_AGREE;
        } else {
            if (PublicUtil.isEmpty(comment)) {
                throw new OmcBizException(ErrorCodeEnum.OMC10031107);
            }
            omcOldmanStatusService.oldmanOutEnd(omcOldOutQuery.getOldmanId());
        }
        taskService.setVariable(task.getId(), OldOutConstant.OLD_OUT_VAR_MSG, msg);

        // 设置用户id
        Authentication.setAuthenticatedUserId(loginAuthDto.getUserName() + "[医疗部]");
        // 添加批注信息
        taskService.addComment(task.getId(), processInstanceId, comment);

        //创建推送请求 医疗部长同意
        SendMessageRequest sendMessageRequest = new SendMessageRequest();
        sendMessageRequest.setGroupId(loginAuthDto.getGroupId());
        if(state.equals(OldOutConstant.OLD_OUT_STATE_MEDICAL_AGREE)){
            sendMessageRequest.setMsgCode(OldOutConstant.OUT_FLOW_MEDICAL_AGREE);
            opcMessageService.pushWithMsgCode(sendMessageRequest);
        //医疗部长拒绝
        }else if(state.equals(OldOutConstant.OLD_OUT_STATE_SERVICE_REFUSE)){
            //获取流程参数
            // Map<String, Object> variable = taskService.getVariables(task.getId());
            //获取申请人id
            //Long applyId = Long.parseLong(variable.get(OldOutConstant.OLD_OUT_VAR_APPLY).toString());
            /**
             * @date    2019-12-09
             * @author  chisj
             * @desc    推送描述信息
             */
            sendMessageRequest.setExtrasParam(omcOldOutQuery);
            Long applyId = omcOldOutQuery.getCreatorId();
            sendMessageRequest.setMsgCode(OldOutConstant.OUT_FLOW_MEDICAL_REFUSE);
            sendMessageRequest.setUserIdList(Lists.newArrayList(applyId));
            sendMessageRequest.setTagList(Lists.newArrayList(JiGuangConstant.TAG_PREFIX_USER + applyId));
            opcMessageService.pushByUser(sendMessageRequest);
        }

        // 完成任务
        taskService.complete(task.getId());

        OmcOldOut omcOldOut = new OmcOldOut();
        omcOldOut.setId(oldOutApprovalDto.getId());
        omcOldOut.setUpdateInfo(loginAuthDto);
        omcOldOut.setState(state);

        return omcOldOutMapper.updateByPrimaryKeySelective(omcOldOut);
    }

    @Override
    public Integer admitApproval(OldOutApprovalDto oldOutApprovalDto, LoginAuthDto loginAuthDto) {

        String processInstanceId;

        // 查询订单是否存在
        OmcOldOut omcOldOutQuery = omcOldOutMapper.selectByPrimaryKey(oldOutApprovalDto.getId());
        if (PublicUtil.isEmpty(omcOldOutQuery)) {
            throw new OmcBizException(ErrorCodeEnum.OMC10032005);
        }

        // 获取当前用户角色
        List<RpcRoleVo> roleVoList = uacRpcService.queryRoleListByUserId(loginAuthDto.getUserId());
        List<String> roleCodeList = roleVoList.stream().map(r -> r.getRoleCode()).collect(Collectors.toList());

        processInstanceId = omcOldOutQuery.getProcessInstanceId();
        Task task = taskService.createTaskQuery()
                .taskTenantId(loginAuthDto.getGroupId().toString())
                .processDefinitionKey(OldOutConstant.PROCESS_KEY_OLD_OUT)
                .taskCandidateGroupIn(roleCodeList)
                .processInstanceId(processInstanceId)
                .taskDefinitionKey(OldOutConstant.OLD_OUT_TASK_ADMIT_CONFIRM)
                .singleResult();

        if (PublicUtil.isEmpty(task)) {
            // TODO 老人出院任务不存在
            Log.error("老人出院任务不存在");
            throw new OmcBizException(ErrorCodeEnum.OMC10032008);
        }

        // String comment = OldOutConstant.OLD_OUT_COMMENT_ADMIT_REFUSE;
        String comment = oldOutApprovalDto.getComment();
        Integer state = OldOutConstant.OLD_OUT_STATE_SERVICE_REFUSE;
        String msg = OldOutConstant.OLD_OUT_VAR_MSG_REFUSE;

        if (oldOutApprovalDto.getState().equals(OldOutConstant.OLD_OUT_APRV_STATE_YES)) {
            msg = OldOutConstant.OLD_OUT_VAR_MSG_CONFIRM;
            state = OldOutConstant.OLD_OUT_STATE_ADMIT_CONFIRM;
            comment = OldOutConstant.OLD_OUT_COMMENT_ADMIT_AGREE;
        } else {
            if (PublicUtil.isEmpty(comment)) {
                throw new OmcBizException(ErrorCodeEnum.OMC10031107);
            }
            omcOldmanStatusService.oldmanOutEnd(omcOldOutQuery.getOldmanId());
        }
        taskService.setVariable(task.getId(), OldOutConstant.OLD_OUT_VAR_MSG, msg);

        // 设置用户id
        Authentication.setAuthenticatedUserId(loginAuthDto.getUserName() + "[接待部]");
        // 添加批注信息
        taskService.addComment(task.getId(), processInstanceId, comment);

        //创建推送请求 接待部长同意
        SendMessageRequest sendMessageRequest = new SendMessageRequest();
        sendMessageRequest.setGroupId(loginAuthDto.getGroupId());
        if(state.equals(OldOutConstant.OLD_OUT_STATE_ADMIT_CONFIRM)){
            sendMessageRequest.setMsgCode(OldOutConstant.OUT_FLOW_ADMIT_CONFIRM);
            opcMessageService.pushWithMsgCode(sendMessageRequest);
        //接待部长拒绝
        }else if(state.equals(OldOutConstant.OLD_OUT_STATE_SERVICE_REFUSE)){
            //获取流程参数
            //Map<String, Object> variable = taskService.getVariables(task.getId());
            //获取申请人id
            //Long applyId = Long.parseLong(variable.get(OldOutConstant.OLD_OUT_VAR_APPLY).toString());
            /**
             * @date    2019-12-09
             * @author  chisj
             * @desc    推送描述信息
             */
            sendMessageRequest.setExtrasParam(omcOldOutQuery);
            Long applyId = omcOldOutQuery.getCreatorId();
            sendMessageRequest.setUserIdList(Lists.newArrayList(applyId));
            sendMessageRequest.setTagList(Lists.newArrayList(JiGuangConstant.TAG_PREFIX_USER + applyId));
            sendMessageRequest.setMsgCode(OldOutConstant.OUT_FLOW_ADMIT_REFUSE);
            opcMessageService.pushByUser(sendMessageRequest);
        }

        // 完成任务
        taskService.complete(task.getId());

        OmcOldOut omcOldOut = new OmcOldOut();
        omcOldOut.setId(oldOutApprovalDto.getId());
        omcOldOut.setUpdateInfo(loginAuthDto);
        omcOldOut.setState(state);

        return omcOldOutMapper.updateByPrimaryKeySelective(omcOldOut);
    }

    @Override
    public Integer chargeConfirm(OldOutConfirmDto oldOutConfirmDto, LoginAuthDto loginAuthDto) {
        String processInstanceId;

        // 查询订单是否存在
        OmcOldOut omcOldOutQuery = omcOldOutMapper.selectByPrimaryKey(oldOutConfirmDto.getId());
        if (PublicUtil.isEmpty(omcOldOutQuery)) {
            throw new OmcBizException(ErrorCodeEnum.OMC10032005);
        }

        // 获取当前用户角色
        List<RpcRoleVo> roleVoList = uacRpcService.queryRoleListByUserId(loginAuthDto.getUserId());
        List<String> roleCodeList = roleVoList.stream().map(r -> r.getRoleCode()).collect(Collectors.toList());

        processInstanceId = omcOldOutQuery.getProcessInstanceId();
        Task task = taskService.createTaskQuery()
                .taskTenantId(loginAuthDto.getGroupId().toString())
                .processDefinitionKey(OldOutConstant.PROCESS_KEY_OLD_OUT)
                .taskCandidateGroupIn(roleCodeList)
                .processInstanceId(processInstanceId)
                .taskDefinitionKey(OldOutConstant.OLD_OUT_TASK_CHARGE_CONFIRM)
                .singleResult();

        if (PublicUtil.isEmpty(task)) {
            // TODO 老人出院任务不存在
            Log.error("老人出院任务不存在");
            throw new OmcBizException(ErrorCodeEnum.OMC10032008);
        }

        String comment = OldOutConstant.OLD_OUT_COMMENT_CHARGE_CONFIRM;
        Integer state = OldOutConstant.OLD_OUT_STATE_CHARGE_CONFIRM;

        omcOldmanStatusService.oldmanOutEnd(omcOldOutQuery.getOldmanId());

        // 设置用户id
        Authentication.setAuthenticatedUserId(loginAuthDto.getUserName() + "[收费室]");
        // 添加批注信息
        taskService.addComment(task.getId(), processInstanceId, comment);

        // 完成任务
        taskService.complete(task.getId());

        OmcOldOut omcOldOut = new OmcOldOut();
        omcOldOut.setId(oldOutConfirmDto.getId());
        omcOldOut.setUpdateInfo(loginAuthDto);
        omcOldOut.setState(state);

        // 老人请假退费结算
        omcOldLeaveService.closeReturnFeeByDate(omcOldOutQuery.getOldmanId(), omcOldOutQuery.getLeaveDate());

        /**
         * 账单入库
         */
        OmcOldManBill omcOldManBill = getOmcOldManBillByOldOut(omcOldOutQuery);
        omcOldManBill.setUpdateInfo(loginAuthDto);
        omcOldManBillService.save(omcOldManBill);

        Long billId = omcOldManBill.getId();

        omcOldOut.setBillId(billId);

        List<OmcBillBackItem> omcBillBackItemList = Lists.newArrayList();
        List<OldOutItemVo> oldOutItemVoList = omcOldOutItemService.queryOldOutItemByOldOutId(omcOldOutQuery.getId());
        for (OldOutItemVo oldOutItemVo : oldOutItemVoList) {
            OmcBillBackItem omcBillBackItem = getOmcBillBackItem(oldOutItemVo, loginAuthDto);
            omcBillBackItem.setBillId(billId);
            omcBillBackItemList.add(omcBillBackItem);
        }

        omcBillBackItemService.batchSave(omcBillBackItemList);

        List<OmcBillMeal> omcBillMealList = Lists.newArrayList();
        List<OmcBillSetMealItem> omcBillSetMealItemList = Lists.newArrayList();
        List<OldOutSetMealVo> oldOutSetMealVoList = omcOldOutSetMealService.queryOldOutSetMealByOldOutId(omcOldOutQuery.getId());
        for (OldOutSetMealVo oosmv : oldOutSetMealVoList) {
            OmcBillMeal omcBillMeal = new OmcBillMeal();
            BeanUtils.copyProperties(oosmv, omcBillMeal);
            omcBillMeal.setGroupId(omcOldOutQuery.getGroupId());
            omcBillMeal.setBillId(omcOldManBill.getId());
            omcBillMeal.setUpdateInfo(loginAuthDto);
            omcBillMealList.add(omcBillMeal);
            for (OldOutSetMealItemVo oostmiv : oosmv.getOldOutSetMealItemVoList()) {
                OmcBillSetMealItem omcBillSetMealItem = new OmcBillSetMealItem();
                BeanUtils.copyProperties(oostmiv, omcBillSetMealItem);
                omcBillSetMealItem.setSetmealId(oosmv.getSetMealId());
                omcBillSetMealItem.setGroupId(omcOldOutQuery.getGroupId());
                omcBillSetMealItem.setBillId(omcOldManBill.getId());
                omcBillSetMealItem.setUpdateInfo(loginAuthDto);
                omcBillSetMealItem.setExpenseItemName(oostmiv.getItemName());
                omcBillSetMealItem.setExpenseTypeName(oostmiv.getItemType());
                omcBillSetMealItem.setChargeStandard(oostmiv.getItemFee());
//                omcBillSetMealItem.setModelCode(oostmiv.getModelCode());
//                omcBillSetMealItem.setRemark(oostmiv.getRemark());
                omcBillSetMealItemList.add(omcBillSetMealItem);
            }
        }
        omcBillMealService.batchSave(omcBillMealList);
        omcBillSetMealItemService.batchSave(omcBillSetMealItemList);

        OmcBillOutHospitalFee omcBillOutHospitalFee = new OmcBillOutHospitalFee();
        omcBillOutHospitalFee.setUpdateInfo(loginAuthDto);
        omcBillOutHospitalFee.setGroupId(loginAuthDto.getGroupId());
        omcBillOutHospitalFee.setBillId(billId);
        omcBillOutHospitalFee.setPayable(omcOldOut.getChargeTotal());
        omcBillOutHospitalFee.setLeaveBackFee(BigDecimal.ZERO); // 需要从天数退款中查询
        omcBillOutHospitalFee.setPeriodBackFee(omcOldOut.getDaysTotal()); // 需要从天数退款中查询
        omcBillOutHospitalFee.setBackTotalFee(omcOldOut.getItemsTotal());

        omcBillOutHospitalFeeMapper.insertSelective(omcBillOutHospitalFee);


        // 修改老人状态以及所在机构
        Oldman oldman = new Oldman();
        oldman.setOldmanId(omcOldOutQuery.getOldmanId());
        oldman.setStatus(Constant.YICHUYUAN);
        Integer type = omcOldOutQuery.getType();
        if (type != null
                && (type.equals(3) || type.equals(4))) {
            oldman.setStatus(Constant.QUSHI);
        }

        // 修改老人的缴费状态 == 》待缴费 cn_omc_oldman_supplement is_payed = 0
//        omcOldManSupplementMapper.clearPayed(omcOldOutQuery.getOldmanId());
        /*
        * 2020-07-29
        * xcr
        * 二次入院
        * 设置为未缴费 清空床位id、入院日期
        * */
        OmcOldManSupplement oldManSupplement = new OmcOldManSupplement();
        oldManSupplement.setOldManId(omcOldOutQuery.getOldmanId().longValue());
        oldManSupplement = omcOldManSupplementService.selectOne(oldManSupplement);
        oldManSupplement.setBedId(null);
        oldManSupplement.setIsPayed(0);
        //oldManSupplement.setInDate(null);
        omcOldManSupplementService.updateById(oldManSupplement);

        /**
         *  需要清除机构
         */
        //oldman.setHomeId(null);
        oldmanService.checkOut(oldman);

        // 清除床位
        if (omcOldOutQuery.getBedId() != null) {
            bedService.cleanOldmanById(omcOldOutQuery.getBedId());
        }

        /*
         * 2020-07-28
         * xcr
         * 二次入院-清空老人入院时选的项目
         * */
        OmcOldmanExpenseItem item = new OmcOldmanExpenseItem();
        item.setOldmanId(oldman.getOldmanId().longValue());
        int j = omcOldmanExpenseItemService.delete(item);

        //创建推送请求 收费室确认
        SendMessageRequest sendMessageRequest = new SendMessageRequest();
        //获取流程参数
        // Map<String, Object> variable = taskService.getVariables(task.getId());
        //获取申请人id
        // Long applyId = Long.parseLong(variable.get(OldOutConstant.OLD_OUT_VAR_APPLY).toString());
        /**
         * @date    2019-12-09
         * @author  chisj
         * @desc    推送描述信息
         */
        sendMessageRequest.setExtrasParam(omcOldOutQuery);
        Long applyId = omcOldOutQuery.getCreatorId();
        sendMessageRequest.setUserIdList(Lists.newArrayList(applyId));
        //创建极光tag
        sendMessageRequest.setTagList(Lists.newArrayList(JiGuangConstant.TAG_PREFIX_USER + applyId));
        sendMessageRequest.setGroupId(loginAuthDto.getGroupId());
        sendMessageRequest.setMsgCode(OldOutConstant.OUT_FLOW_CHARGE_CONFIRM);
        opcMessageService.pushByUser(sendMessageRequest);

        return omcOldOutMapper.updateByPrimaryKeySelective(omcOldOut);
    }

    private OmcBillBackItem getOmcBillBackItem(OldOutItemVo oldOutItemVo, LoginAuthDto loginAuthDto) {

        OmcBillBackItem omcBillBackItem = new OmcBillBackItem();

        BeanUtils.copyProperties(oldOutItemVo, omcBillBackItem);
        omcBillBackItem.setUpdateInfo(loginAuthDto);
        omcBillBackItem.setBackFee(oldOutItemVo.getTotalFee());

        return omcBillBackItem;
    }

    private OmcOldManBill getOmcOldManBillByOldOut(OmcOldOut omcOldOut) {

        OmcOldManBill omcOldManBill = new OmcOldManBill();

        //写入老人名字
        Oldman oldman = new Oldman();
        oldman.setOldmanId(omcOldOut.getOldmanId());
        Oldman old = oldmanService.selectByOld(oldman);

        omcOldManBill.setBillNumber(com.csun.cmny.provider.utils.DateUtil
                .getPayNumber(omcOldOut.getGroupId()));
        omcOldManBill.setOldManId((long) omcOldOut.getOldmanId());
        omcOldManBill.setGroupId(omcOldOut.getGroupId());
        omcOldManBill.setIsPay(1);
        omcOldManBill.setTotalPay(omcOldOut.getTotalPay());
        omcOldManBill.setPayTime(new Date());
        omcOldManBill.setBillType(2);
        omcOldManBill.setInDate(omcOldOut.getInDate());
        omcOldManBill.setOldManName(old.getOldName());

        return omcOldManBill;

    }

    /**
     * 查询可出院的老人列表
     *
     * @param oldOutOldmanQueryDto the old out oldman query dto
     * @return the old out oldman man list
     */
    @Override
    public List<OldOutOldmanVo> queryOldmanList(OldOutOldmanQueryDto oldOutOldmanQueryDto) {

        List<Integer> statusList = Lists.newArrayList();
        statusList.add(Constant.YIRUYUAN);
        statusList.add(Constant.SHIRUZHU);
        oldOutOldmanQueryDto.setOldmanStateList(statusList);

        List<Integer> stateList = Lists.newArrayList();
        stateList.add(OldOutConstant.OLD_OUT_STATE_SERVICE_REFUSE);
        stateList.add(OldOutConstant.OLD_OUT_STATE_CHARGE_CONFIRM);
        oldOutOldmanQueryDto.setStateList(stateList);

        return omcOldOutMapper.queryOldmanList(oldOutOldmanQueryDto);
    }

    /**
     * 根据账单Id查询老人出院账单
     *
     * @param billId 账单Id
     * @return the old out vo
     */
    @Override
    public OldOutVo queryByBillId(Long billId) {

        // 根据billId查询老人出院Id
        OmcOldOut omcOldOut = new OmcOldOut();
        omcOldOut.setBillId(billId);
        omcOldOut = omcOldOutMapper.selectOne(omcOldOut);
        if (omcOldOut == null) {
            return  null;
        }

        return queryById(omcOldOut.getId());
    }

    @Override
    public List<Integer> queryCurTaskStates(LoginAuthDto loginAuthDto) {
        List<Integer> states = Lists.newArrayList();

        Map<String, Object> outVarMap = omcOldOutVarService
                .queryVarByGroupId(loginAuthDto.getGroupId());

        // 获取当前用户角色
        List<RpcRoleVo> roleVoList = uacRpcService.queryRoleListByUserId(loginAuthDto.getUserId());
        for (RpcRoleVo r : roleVoList) {
            if (outVarMap.get(OldOutConstant.OLD_OUT_VAR_SERVICE).toString().contains(r.getRoleCode())) {
                // 服务部长角色（服务部长） ===> 查看提交申请的任务
                states.add(OldOutConstant.OLD_OUT_STATE_APPLY);
            }
            if (outVarMap.get(OldOutConstant.OLD_OUT_VAR_ADMIT).toString().contains(r.getRoleCode())) {
                // 接待角色（接待员、接待部长、评估员） ===> 查看服务部长确认的任务
                states.add(OldOutConstant.OLD_OUT_STATE_MEDICAL_AGREE);
            }
            if (outVarMap.get(OldOutConstant.OLD_OUT_VAR_CHARGE).toString().contains(r.getRoleCode())) {
                // 收费员角色（收费员） ===> 查看接待部确认的任务
                states.add(OldOutConstant.OLD_OUT_STATE_ADMIT_CONFIRM);
            }
            if (outVarMap.get(OldOutConstant.OLD_OUT_VAR_MEDICAL).toString().contains(r.getRoleCode())) {
                // 医疗部长） ===> 查看接待部确认的任务
                states.add(OldOutConstant.OLD_OUT_STATE_SERVICE_AGREE);
            }
        }
        return states;
    }


    /**
     * query omc old out vo list with page
     *
     * @param oldOutQueryDto    the old out query dto
     *
     * @return  the old out vo list
     */
    @Override
    public List<OldOutVo> queryListWithPage(OldOutQueryDto oldOutQueryDto) {

        return omcOldOutMapper.queryListWithPage(oldOutQueryDto);
    }

    /**
     * query oldOut comment by oldOut id
     *
     * @param id    the revise id
     *
     * @return  the revise comment list
     */
    @Override
    public List<MyCommentVo> queryCommentById(Long id) {
        // 查询调房调级基本信息
        OmcOldOut omcOldOut = omcOldOutMapper.selectByPrimaryKey(id);
        if (PublicUtil.isEmpty(omcOldOut)) {
            throw new OmcBizException(ErrorCodeEnum.OMC10040003);
        }

        List<MyCommentVo> myCommentVoList = Lists.newArrayList();

        // 根据流程Id查询批注
        String processInstanceId = omcOldOut.getProcessInstanceId();
        List<Comment> commentList = taskService.getProcessInstanceComments(processInstanceId);
        for (Comment c : commentList) {
            MyCommentVo myCommentVo = new MyCommentVo();
            myCommentVo.setUserId(c.getUserId());
            myCommentVo.setMessage(c.getFullMessage());
            myCommentVo.setTime(c.getTime());

            myCommentVoList.add(myCommentVo);
        }

        Collections.reverse(myCommentVoList);

        return myCommentVoList;
    }

    /**
     * query old out vo by old out id
     *
     * @param id the old out id
     *
     * @return the old out vo
     */
    @Override
    public OldOutVo queryById(Long id) {

        OldOutQueryDto oldOutQueryDto = new OldOutQueryDto();
        oldOutQueryDto.setOldOutId(id);
        PageHelper.startPage(1, 1);
        List<OldOutVo> oldOutVoList = omcOldOutMapper.queryListWithPage(oldOutQueryDto);
        if (PublicUtil.isEmpty(oldOutVoList) || oldOutVoList.size() < 1) {
            throw new OmcBizException(ErrorCodeEnum.OMC10040004);
        }

        OldOutVo oldOutVo = oldOutVoList.get(0);

        // 查询老人收费/退费项
        List<OldOutItemVo> oldOutItemVoList = omcOldOutItemService.queryOldOutItemByOldOutId(id);
        oldOutVo.setOldOutItemVoList(oldOutItemVoList);

        // 查询老人套餐退费
        List<OldOutSetMealVo> oldOutSetMealVoList = omcOldOutSetMealService.queryOldOutSetMealByOldOutId(id);
        oldOutVo.setOldOutSetMealVoList(oldOutSetMealVoList);

        // 查询老人天数退款
        List<OldOutDaysFeeVo> oldOutDaysFeeVoList = omcOldOutDaysService.queryOldOutDaysFeeByOldOutId(id);
        oldOutVo.setOldOutDaysVoList(oldOutDaysFeeVoList);

        return oldOutVo;
    }
}
